随笔分类
线程的底层封装
参考:https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html
须有一定OS和JVM基础再来观看此文
与Linux下的JVM为例
JVM下的线程是要和OS中的线程(Pthreads)对接的
线程在创建后并不会直接去os进行对接
想要深入了解juc,应当先从基础看起
Java下的new Thread()只是Java层面一个线程创建,真正执行时还需要与OS挂钩
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) { //显然,只是为JVM中thread分配内存空间以及任务而已
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
只有真正调用start()时才会去和os进行交互
以Linux为例,start0()是与pthread建立联系的一个点
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();//调用了start0()方法
started = true;//调用之后started变为了true,线程已经启动,关键点在于start0()
} finally {
try {
if (!started) {
group.threadStartFailed(this);//如果标志位没变,即线程启动失败
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();//JNI,真相了,JVM帮我们去调用系统底层
接着来探讨下JNI了,
先来看看Thread的一段描述
// Base class for all threads: VMThread, WatcherThread, ConcurrentMarkSweepThread(高并发下的标记清除Thread),
//Thread是所有thread的基类,4种类型
// JavaThread --这是我们所有探讨的javaThread
Thread::Thread() {
jvm.cpp,创建一个JavaThread,C++级别的线程
native_thread = new JavaThread(&thread_entry, sz);//创建一个JavaThread,即创建一个C++级别实质上是Java的线程
static void thread_entry(JavaThread* thread, TRAPS) { //接收一个指针,Java中线程在调用start时就已经把自己传进来了,然后来执行这个方法
HandleMark hm(THREAD);
Handle obj(THREAD, thread->threadObj());
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
obj,
KlassHandle(THREAD, SystemDictionary::Thread_klass()),
vmSymbols::run_method_name(),
vmSymbols::void_method_signature(),
THREAD);
}
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
再来查看下JavaThread方法
thread.cpp,可以看到它创建了一个系统线程
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
Thread()
#if INCLUDE_ALL_GCS
, _satb_mark_queue(&_satb_mark_queue_set),
_dirty_card_queue(&_dirty_card_queue_set)
#endif // INCLUDE_ALL_GCS
{
if (TraceThreadEvents) {
tty->print_cr("creating thread %p", this);
}
initialize();
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);
// Create the native thread itself.
// %note runtime_23
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : //显然这里会是java_thread
os::java_thread;
os::create_thread(this, thr_type, stack_sz);//这时通过thr_type(也就是java_thread)来创建一个os级别的线程
_safepoint_visible = false;
这时候来看看os::create_thread --> 看linux下的
os_linux.cpp
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {//这里的thread,也就是之前的JavaThread,传了指针过来
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);//创建一个OS级别的线程
if (osthread == NULL) {
return false;
}
// set the correct thread state
osthread->set_thread_type(thr_type);//即该osthread的类别是用户线程,即JavaThread
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);//该线程已经分配,但还未进行初始化
thread->set_osthread(osthread);//将用户线程与OS下的线程绑定,即让哪个osthread去执行哪个JavaThread
// init thread attributes 这里才开始真正的pthread!
pthread_attr_t attr;
pthread_attr_init(&attr);//为pthread分配资源,相当于c++下的pthread_attr_init(&attr),得到默认属性
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
....
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);//创建pthread,这里的java_start其实就是分配的任务了,thread即JavaThread
//这里的pthread_create方法实际上就是最终创建系统线程的方法,这里才真正映射到系统层面
pthread_attr_destroy(&attr);
// Thread start routine for all newly created threads
static void *java_start(Thread *thread) {
// Try to randomize the cache line index of hot stack frames.
// This helps when threads of the same stack traces evict each other's
// cache lines. The threads can be either from the same JVM instance, or
// from different JVM instances. The benefit is especially true for
// processors with hyperthreading technology.
static int counter = 0;
int pid = os::current_process_id();//得到OS当前进程的id
alloca(((pid ^ counter++) & 7) * 128);
ThreadLocalStorage::set_thread(thread);
OSThread* osthread = thread->osthread();//通过thread绑定的osthread,来得到当前osthread
Monitor* sync = osthread->startThread_lock();//得到一把锁,monitor,进入、离开,需要进行同步
// non floating stack LinuxThreads needs extra check, see above
if (!_thread_safety_check(thread)) {
// notify parent thread
MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
osthread->set_state(ZOMBIE);
sync->notify_all();
return NULL;
}
// thread_id is kernel thread id (similar to Solaris LWP id)
osthread->set_thread_id(os::Linux::gettid());//为当前osthread设置id,这里的is是os内核线程的id
那么锁有什么用呢?
phread还没有运行起来呢,现在只是出于分配未初始化状态
接着看
// handshaking with parent thread
{
MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
// notify parent thread
osthread->set_state(INITIALIZED);//设置为初始化状态
sync->notify_all();
// wait until os::start_thread() 阻塞,直到os调用start_thread() --即让当前创建的子线程去工作
while (osthread->get_state() == INITIALIZED) {//处于已经初始化但还未运行时
sync->wait(Mutex::_no_safepoint_check_flag);//互斥锁,当前创建的线程阻塞了,等待被调度
}
}
// call one more level start routine
thread->run();
回到jvm.cpp
//jvm.cpp
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) //语义很明确,准备去启动线程
Thread::start(native_thread);//启动线程,这里的native也就是一开始说的JavaThread了
JVM_END
void Thread::start(Thread* thread) {
trace("start", thread);
// Start is different from resume in that its safety is guaranteed by context or
// being called from a Java method synchronized on the Thread object.
if (!DisableStartThread) {
if (thread->is_Java_thread()) {
// Initialize the thread state to RUNNABLE before starting this thread.
// Can not set it after the thread started because we do not know the
// exact thread state at that time. It could be in MONITOR_WAIT or
// in SLEEPING or some other state.
java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
java_lang_Thread::RUNNABLE);
}
os::start_thread(thread);//真相了,os调用了start_thread方法,之前的osthread不再等待阻塞了
}
}
再次回到linux.cpp
// wait until os::start_thread() 阻塞,直到os调用start_thread() --即让当前创建的子线程去工作
while (osthread->get_state() == INITIALIZED) {//处于已经初始化但还未运行时
sync->wait(Mutex::_no_safepoint_check_flag);//互斥锁,当前创建的线程阻塞了,等待被调度
}
}
// call one more level start routine
thread->run();//os内核线程开始工作
return 0;
}